package com.lfy.aop;

import com.lfy.aop.anno.CheckFile;
import com.lfy.aop.enums.FileMagicTypeEnum;
import com.lfy.aop.enums.LegalFileTypeEnum;
import com.lfy.modules.common.custom.constants.FileConstant;
import com.lfy.modules.common.domain.R;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.Objects;

/**
 * 文件魔术校验
 *
 * @author <a href="https://www.lvfeiy.top">lvfeiyang</a>
 * @date 2024/5/27 19:55
 */
@Component
@Aspect
@Slf4j
public class checkFileAspect {
    @Pointcut(value = "@annotation(com.lfy.aop.anno.CheckFile)")
    public void cut() {

    }

    @SneakyThrows
    @Around("cut()")
    public Object checkFile(ProceedingJoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        MethodSignature method = (MethodSignature) joinPoint.getSignature();
        CheckFile checkFile = method.getMethod().getAnnotation(CheckFile.class);
        for (Object arg : args) {
            if (arg instanceof MultipartFile[]) {
                MultipartFile[] files = (MultipartFile[]) arg;
                for (MultipartFile file : files) {
                    try {
                        checkFileHandler(file,checkFile);
                    } catch (Exception e) {
                        return R.error(e.getMessage());
                    }
                }
            } else if (arg instanceof MultipartFile) {
                MultipartFile file = (MultipartFile) arg;
                try {
                    checkFileHandler(file,checkFile);
                } catch (Exception e) {
                    return R.error(e.getMessage());
                }
            }
        }
        return joinPoint.proceed();
    }
    private static void checkFileHandler(MultipartFile file,CheckFile checkFile) throws Exception {
        if (file.isEmpty()) {
            throw new IllegalArgumentException("文件不存在");
        }
        if (file.getSize() > FileConstant.MAX_IMG_FILE_SIZE) {
            throw new IllegalArgumentException("文件大小不能超过10M");
        }
        LegalFileTypeEnum[] enums = checkFile.value();

        detectFileType(file,enums);




    }
    private static void detectFileType(MultipartFile file, LegalFileTypeEnum[] enums) throws IOException {

        InputStream inputStream = file.getInputStream();
        byte[] bytes = new byte[4];
        inputStream.read(bytes);
        String head = toHexString(bytes);
        log.info("文件头：" +head);
        inputStream.close();
        //高危文件类型校验
        String extension = FileMagicTypeEnum.getExtension(head);
        if(!StringUtils.isBlank(extension)){
            throw new IllegalArgumentException("文件类型不允许上传");
        }
        //指定文件类型校验
        if(Objects.nonNull(enums) && enums.length>0){
            for (LegalFileTypeEnum anEnum : enums) {
                if(anEnum.getHexHeader().startsWith(head) || head.startsWith(anEnum.getHexHeader())){
                   return;
                }
            }
            throw new IllegalArgumentException("文件类型不允许上传");
        }


    }
    private static String toHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X", b & 0xFF));
        }
        return sb.toString().replace(" ", "");
    }

}
